#include "stdafx.h"
#include "SimpleEventTestSuite.h"

namespace CO { namespace SpiFoundation { namespace RoomFW {

SimpleEventTestSuite::SimpleEventTestSuite(void)
{
	TEST_ADD(SimpleEventTestSuite::manualSignaled)
	TEST_ADD(SimpleEventTestSuite::manualUnsignaled)
	TEST_ADD(SimpleEventTestSuite::autoSignaled)
	TEST_ADD(SimpleEventTestSuite::autoUnsignaled)
	TEST_ADD(SimpleEventTestSuite::copy)
	TEST_ADD(SimpleEventTestSuite::close)
	TEST_ADD(SimpleEventTestSuite::wait)
}

void SimpleEventTestSuite::manualSignaled(void)
{
	// Create an event
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(true, true));

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "initially signaled");

	// Test still signaled.
	TEST_ASSERT_MSG(evt.wait(0), "manual reset");

	// Test reset
	TEST_ASSERT_MSG(evt.reset(), "reset");

	// Test not still signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "not signaled");

	// Test set.
	TEST_ASSERT_MSG(evt.set(), "set");

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "signaled");
}

void SimpleEventTestSuite::manualUnsignaled(void)
{
	// Create an event
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(true, false));

	// Test not signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "initially unsignaled");

	// Test set.
	TEST_ASSERT_MSG(evt.set(), "set");

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "signaled");

	// Test still signaled.
	TEST_ASSERT_MSG(evt.wait(0), "manual reset");

	// Test reset
	TEST_ASSERT_MSG(evt.reset(), "reset");

	// Test not still signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "not signaled");
}

void SimpleEventTestSuite::autoSignaled(void)
{
	// Create an event
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(false, true));

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "initially signaled");

	// Test not still signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "auto reset");

	// Test set.
	TEST_ASSERT_MSG(evt.set(), "set");

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "signaled");

	// Test not still signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "auto reset");
}

void SimpleEventTestSuite::autoUnsignaled(void)
{
	// Create an event
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(false, false));

	// Test not signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "initially unsignaled");

	// Test set.
	TEST_ASSERT_MSG(evt.set(), "set");

	// Test signaled.
	TEST_ASSERT_MSG(evt.wait(0), "signaled");

	// Test not still signaled.
	TEST_ASSERT_MSG(!evt.wait(0), "auto reset");
}

void SimpleEventTestSuite::copy(void)
{
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(true, true));
	TEST_ASSERT(evt.wait(0));
	{
		CO::SpiFoundation::RoomFW::SimpleEvent evt2 = evt;
		TEST_ASSERT(evt2.wait(0));
	}
	TEST_ASSERT(evt.wait(0));
}

void SimpleEventTestSuite::close(void)
{
	CO::SpiFoundation::RoomFW::SimpleEvent evt;
	TEST_ASSERT(evt.create(true, true));
	TEST_ASSERT(evt.wait(0));
	HANDLE handle = evt; // test implicit cast.
	TEST_ASSERT(0 != handle);
	evt.close();
	TEST_ASSERT(0 == evt);
	DWORD wait = ::WaitForSingleObject(handle, 0);
	DWORD error = ::GetLastError();
	TEST_ASSERT(WAIT_FAILED == wait);
	TEST_ASSERT(ERROR_INVALID_HANDLE == error);
}

void SimpleEventTestSuite::wait(void)
{
	CO::SpiFoundation::RoomFW::SimpleEvent first;
	CO::SpiFoundation::RoomFW::SimpleEvent second;
	TEST_ASSERT(first.create(false, false));
	TEST_ASSERT(second.create(false, false));
	EventPair pair(first, second);
	ThreadArg arg(this, &pair);
	TEST_ASSERT(1L != ::_beginthread(ThreadProc, 0, &arg));
	TEST_ASSERT(pair.first.set());
	TEST_ASSERT(pair.second.wait(MaxWait));
}

void SimpleEventTestSuite::ThreadProc(void* arg)
{
	ThreadArg* ta = static_cast<ThreadArg*>(arg);
	ta->first->waitProc(ta->second); // Can only TEST_ASSERT in non-static method.
}

void SimpleEventTestSuite::waitProc(EventPair* pair)
{
	TEST_ASSERT(pair->first.wait(MaxWait));
	TEST_ASSERT(pair->second.set());
}

}}}
